//--------------------------------------------------------------------------
// $Id: MacSignatory.java 10 2006-08-21 13:48:09Z zendragon $
//--------------------------------------------------------------------------
// Copyright 2006 Social Brain Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//--------------------------------------------------------------------------

package org.socialbrain.openid.security;

import org.socialbrain.openid.Constants;
import org.socialbrain.openid.KeyValuePairs;
import org.socialbrain.openid.OpenIdException;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

/**
 * @author <a href="http://erning.net/">Zhang Erning</a>
 * @version $Id: MacSignatory.java 10 2006-08-21 13:48:09Z zendragon $
 */
public class MacSignatory implements Signatory
{
    public boolean isAcceptAssocType(String assocType)
    {
        return StringUtils.equals(_acceptedAssocType, assocType);
    }

    public byte[] sign(byte[] secret, KeyValuePairs pairs, String[] signed)
    {
        KeyValuePairs linkedPairs = new LinkedKeyValuePairs();
        for (String key : signed)
        {
            linkedPairs.put(key, pairs.get(key));
        }
        String fs = linkedPairs.toFormString();
        if (_logger.isDebugEnabled())
        {
            _logger.debug(String.format("Key-value form to be signed is\n%s[%s]", fs, _macAlgorithm));
        }

        try
        {
            Key key = new SecretKeySpec(secret, _macAlgorithm);
            Mac mac = Mac.getInstance(_macAlgorithm);
            mac.init(key);
            return mac.doFinal(fs.getBytes(Constants.FORM_STRING_ENCODING));
        }
        catch (InvalidKeyException e)
        {
            throw new OpenIdException("MAC key provided is invalid", e);
        }
        catch (NoSuchAlgorithmException e)
        {
            throw new OpenIdException(String.format("Mac algorithm %s is not supported", _macAlgorithm), e);
        }
        catch (Exception e)
        {
            throw new OpenIdException("sign failure", e);
        }
    }

    public byte[] generateKey()
    {
        try
        {
            return KeyGenerator.getInstance(_macAlgorithm).generateKey().getEncoded();
        }
        catch (NoSuchAlgorithmException e)
        {
            throw new OpenIdException(String.format("Mac algorithm %s is not supported", _macAlgorithm), e);
        }
    }

    //

    @Override
    public String toString()
    {
        return String.format("AcceptedAssocType: %s, MacAlgorithm: %s", _acceptedAssocType, _macAlgorithm);
    }

    //

    public void setAcceptedAssocType(String value)
    {
        _acceptedAssocType = value;
    }

    public String getAcceptedAssocType()
    {
        return _acceptedAssocType;
    }

    public void setMacAlgorithm(String value)
    {
        _macAlgorithm = value;
    }

    public String getMacAlgorithm()
    {
        return _macAlgorithm;
    }

    private String _acceptedAssocType;
    private String _macAlgorithm;

    private transient static final Log _logger = LogFactory.getLog(MacSignatory.class);
}
